package com.bolt.admin.security.shiro.jwt;


import com.bolt.admin.properties.LoginProperties;
import com.bolt.common.BoltConstants;
import com.bolt.common.codec.Base64;
import com.bolt.common.utils.DateUtil;
import com.bolt.common.utils.UidUtil;
import com.bolt.support.cache.redis.RedisManager;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
public class TokenProvider {

    private final RedisManager redisManager;

    private final LoginProperties loginProperties;

    private JwtParser jwtParser;
    private JwtBuilder jwtBuilder;

    private static final String AUTHORITIES_KEY = "auth";

    public TokenProvider(RedisManager redisManager, LoginProperties loginProperties) {
        this.redisManager = redisManager;
        this.loginProperties = loginProperties;
    }

    @PostConstruct
    public void afterPropertiesSet() {
        String secret = this.loginProperties.getJwt().getSecret();
        byte[] keyBytes = Base64.decode(secret);
        Key key = Keys.hmacShaKeyFor(keyBytes);
        jwtParser = Jwts.parserBuilder()
                .setSigningKey(key)
                .build();
        jwtBuilder = Jwts.builder()
                .signWith(key, SignatureAlgorithm.HS512);
    }

    /**
     * 创建Token 设置永不过期，
     * Token 的时间有效性转到Redis 维护
     * @param username
     * @return
     */
    public String createToken(String username) {
        return jwtBuilder
                // 加入ID确保生成的 Token 都不一致
                .setId(UidUtil.UID())
                .claim(AUTHORITIES_KEY, username)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        String username;
        try {
            final Claims claims = getClaims(token);
            username = (String)claims.get(AUTHORITIES_KEY);
        } catch (ExpiredJwtException ex) {
            username = ex.getClaims().getSubject();
        }
        return username;
    }

    public Claims getClaims(String token) {
        return jwtParser
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 需要检查的token
     * @param token
     */
    public void checkRenewal(String token) {
        // 判断是否续期token,计算token的过期时间

        String onlineKey = BoltConstants.ONLINEKEY;
        long detect  = loginProperties.getJwt().getDetect();
        long renew =  loginProperties.getJwt().getRenew();
        long time = redisManager.getExpire(onlineKey + token) * 1000;

        Date expireDate = DateUtil.offsetMillisecond(new Date(), (int) time);
        // 判断当前时间与过期时间的时间差
        long differ = expireDate.getTime() - System.currentTimeMillis();
        // 如果在续期检查的范围内，则续期
        if (differ <= detect) {
            long newRenew = time +renew;
            redisManager.expire(onlineKey + token, newRenew, TimeUnit.MILLISECONDS);
        }
    }

    public void parseToken(String token) throws ExpiredJwtException,
            UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
        jwtParser
                .parseClaimsJws(token);

    }

    public String getToken(HttpServletRequest request) {
        final String bearerToken = request.getHeader(BoltConstants.AUTH_HEADER);
        final String startsWith =  this.loginProperties.getJwt().getTokenStartWith();
        if (bearerToken != null && bearerToken.startsWith(startsWith)) {
            // 去掉令牌前缀
            return bearerToken.replace(startsWith, "");
        }
        return bearerToken;
    }

}

 